package com.tuling.circulardependencies;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.util.ConcurrentReferenceHashMap;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/***
 * @Author 徐庶   QQ:1092002729
 * @Slogan 致敬大师，致敬未来的你
 */
public class MainStart {

	private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentReferenceHashMap<>(256);

	//一级缓存
	private static final Map<String, Object> singletonObjects = new ConcurrentReferenceHashMap<>();

	//二级缓存 为了将成熟Bean和纯洁Bean分离，避免并发过程中获取到不完整的Bean
	private static final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();

	//三级缓存
	private static final Map<String, ObjectFactory> singletonFactories = new ConcurrentHashMap<>();

	//循环依赖标识
	private static final Set<String> singletonsCurrentlyInCreation = new HashSet<>();

	/**
	 * 读取Bean定义
	 */
	private static void loadBeanDefinitions() {
		RootBeanDefinition aRootBeanDefinition = new RootBeanDefinition(InstanceA.class);
		RootBeanDefinition bRootBeanDefinition = new RootBeanDefinition(InstanceB.class);
		beanDefinitionMap.put("instanceA", aRootBeanDefinition);
		beanDefinitionMap.put("instanceB", bRootBeanDefinition);
	}

	public static void main(String[] args) throws Exception {
		//加载BeanDefinition
		loadBeanDefinitions();

		for (String beanName : beanDefinitionMap.keySet()) {
			Object bean = getBean(beanName);
			System.out.println(bean);
		}

		InstanceA instanceA = (InstanceA) getBean("instanceA");
		instanceA.say();
	}

	private static Object getBean(String beanName) throws Exception {
		Object singleton = getSingleton(beanName);
		if (singleton != null) {
			return singleton;
		}

		synchronized (singletonObjects) {
			singleton = getSingleton(beanName);
			if (singleton != null) {
				return singleton;
			}
			//正在创建
			if (!singletonsCurrentlyInCreation.contains(beanName)) {
				singletonsCurrentlyInCreation.add(beanName);
			}

			//实例化
			RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
			Class<?> beanClass = beanDefinition.getBeanClass();
			Object instanceBean = beanClass.newInstance();            //无参构造

			//放入三级缓存
			singletonFactories.put(beanName, () -> new JdkProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName), beanName));

			//属性赋值
			Field[] declaredFields = beanClass.getDeclaredFields();
			for (Field field : declaredFields) {
				Autowired annotation = field.getAnnotation(Autowired.class);
				if (annotation != null) {
					field.setAccessible(true);
					//byName byType byConstructor
					Object fieldBean = getBean(field.getName());
					field.set(instanceBean, fieldBean);
				}
			}

			//初始化

			// 由于递归完后A 还是原实例，， 所以要从二级缓存中拿到proxy 。
			if (earlySingletonObjects.containsKey(beanName)) {
				instanceBean = earlySingletonObjects.get(beanName);
			}

			//放入一级缓存
			singletonObjects.put(beanName, instanceBean);
			return instanceBean;
		}
	}

	private static Object getSingleton(String beanName) {
		Object bean = singletonObjects.get(beanName);

		//说明是循环依赖
		if (bean == null && singletonsCurrentlyInCreation.contains(beanName)) {
			synchronized (singletonObjects) {
				// 如果二级缓存没有就从三级缓存中拿
				bean = earlySingletonObjects.get(beanName);
				if (bean == null) {
					// 从三级缓存中拿
					ObjectFactory objectFactory = singletonFactories.get(beanName);
					if (objectFactory != null) {
						earlySingletonObjects.put(beanName, objectFactory.getObject());
					}
				}
			}
		}

		return bean;
	}
}
